//
//  ViewController.m
//  UI25-GCD调研
//
//  Created by dllo on 16/8/17.
//  Copyright © 2016年 DM.C. All rights reserved.
//

#import "ViewController.h"
#define kUrl @"http://img4.duitang.com/uploads/blog/201602/05/20160205185029_ZKz2A.jpeg"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *leftImageView;
@property (weak, nonatomic) IBOutlet UIImageView *rightImageView;
@property (weak, nonatomic) IBOutlet UIImageView *mainImageView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    /**
     调研GCD的方式
     http://www.cnblogs.com/wendingding/p/3807716.html
     http://www.cnblogs.com/wendingding/p/3807265.html
     http://www.mamicode.com/info-detail-862499.html
     通过这三个网址的博客
     查看头文件API
     */


    
   }
- (IBAction)startButton:(id)sender {
    // 创建串行队列, 提交同步任务
    [self createSerial_sync];
        // 自定义串行队列, 提交异步任务
//    [self createSerial_Async];
        // 在主队列中提交异步任务
//    [self createMain_Async];
        //在后台(全局)队列提交同步任务
//    [self createGlobal_sync];
        //在后台(全局)队列提交异步任务
//    [self createGlobal_async];
        // 自定义并行队列，提交同步任务
//    [self createConcurrent_sync];
        // 自定义并行队列，提交异步任务
//    [self createConcurrent_Async];
    // 在主线程中操作
    dispatch_async(dispatch_get_main_queue(), ^{
//         下载一张图片
        [self downImage_main];
        NSLog(@"main队列执行顺序零");
    });
}
- (void)contents {
    // Serial串行
    // 任务串行，意味着在同一时间，有且只有一个任务被执行，即一个任务执行完毕之后再执行下一个任务。
    // Concurrent并发
    // 任务并发，意味着在同一时间，有多个任务被执行
    /**
     同步（Synchronous）与  异步 （Asynchronous）
     
     同步，意味着在当前线程中执行任务，不具备开启新的线程的能力。
     
     异步，在新的线程中执行任务，具备开启新的线程的能力。
     
     在 GCD 中，这些术语描述当一个函数相对于另一个任务完成，此任务是该函数要求 GCD 执行的。一个同步函数只在完成了它预定的任务后才返回。
     
     一个异步函数，刚好相反，会立即返回，预定的任务会完成但不会等它完成。因此，一个异步函数不会阻塞当前线程去执行下一个函数。
     
     临界区（Critical Section）
     
     就是一段代码不能被并发执行，也就是，两个线程不能同时执行这段代码。这很常见，因为代码去操作一个共享资源，例如一个变量若能被并发进程访问，那么它很可能会变质（它的值不再可信）。
     
     死锁（Deadlock）
     
     停止等待事情的线程会导致多个线程相互维持等待，即死锁。
     
     两个（有时更多）东西——在大多数情况下，是线程——所谓的死锁是指它们都卡住了，并等待对方完成或执行其它操作。第一个不能完成是因为它在等待第二个的完成。但第二个也不能完成，因为它在等待第一个的完成。
     */
}
// 创建串行队列, 提交同步任务, 队列的任务是同步出列，任务一执行结束后执行任务二。这种类型的任务与主线程是同步的，会阻塞主线程)
- (void)createSerial_sync{
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        [self downImage_left];
        NSLog(@"执行顺序一一");
    });
    dispatch_sync(queue, ^{
        [self downImage_right];
        NSLog(@"执行顺序二二");
    });
}
// 自定义串行队列, 提交异步任务, 队列的任务是同步出列，任务一执行结束后执行任务二。该类型的任务与主线程是并发执行的，不会阻塞主线程
- (void)createSerial_Async {
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"执行顺序一一");
        [self downImage_left];
    });
    dispatch_async(queue, ^{
        NSLog(@"执行顺序二二");
        [self downImage_right];
    });
   
}
// 自定义并行队列，提交同步任务, 队列的任务是异步出列，任务的出列顺序按先进先出的顺序执行，既任务一出列后任务二接着出列（任务一与任务二又是同步的），与主线程同步，会阻塞主线程
- (void)createConcurrent_sync {
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"执行顺序一一");
        [self downImage_left];
    });
    dispatch_async(queue, ^{
        NSLog(@"执行顺序二二");
        [self downImage_right];
    });
}
// 自定义并行队列，提交异步任务, 任务一出列后任务二才可以出列，各任务之间是异步的，不会阻塞主线程
- (void)createConcurrent_Async {
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"执行顺序一一");
        [self downImage_left];
    });
    dispatch_async(queue, ^{
        NSLog(@"执行顺序二二");
        [self downImage_right];
    });
}
// 在主队列中提交异步任务
- (void)createMain_Async {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 异步任务代码
        [self downImage_left];
        NSLog(@"main队列执行顺序一");
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        // 异步任务代码
        [self downImage_right];
        NSLog(@"main队列执行顺序二");
    });

}
//在后台(全局)队列提交同步任务
- (void)createGlobal_sync {
    /**
     dispatch_get_gloabal_queue 的第一个参数为枚举类型（默认为0），决定任务的优先级 ，第二个参数为Apple保留参数，传0
     #define DISPATCH_QUEUE_PRIORITY_HIGH        2
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT     0
     #define DISPATCH_QUEUE_PRIORITY_LOW         (-2)
     #define DISPATCH_QUEUE_PRIORITY_BACKGROUND  INT16_MIN（后台任务，优先级最低）
     */
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        //code
        [self downImage_left];
        NSLog(@"全局(后台)队列执行顺序一");
    });
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        //code
        [self downImage_right];
        NSLog(@"全局(后台)队列执行顺序二");
    });
}
//在后台(全局)队列提交异步任务
- (void)createGlobal_async {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //code
        [self downImage_left];
        NSLog(@"全局(后台)队列执行顺序一");
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //code
        [self downImage_right];
        NSLog(@"全局(后台)队列执行顺序二");
    });
}
// 例子: 创建一个下载图片的方法, 并在主线程中显示图片(UI的操作)
- (void)downImage_left {
    NSURL *url = [NSURL URLWithString:kUrl];
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    // 回到主线程显示图片
    dispatch_async(dispatch_get_main_queue(), ^{
        _leftImageView.image = image;
    });
}
- (void)downImage_right {
    NSURL *url = [NSURL URLWithString:kUrl];
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    // 回到主线程显示图片
    dispatch_async(dispatch_get_main_queue(), ^{
        _rightImageView.image = image;
    });
}
- (void)downImage_main {
    NSURL *url = [NSURL URLWithString:kUrl];
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    _mainImageView.image = image;
}
// GCD的一些方法
- (void)dispatch {
    // 主线程执行操作
    dispatch_async(dispatch_get_main_queue(), ^{
        
    });
    // 后台执行(标识符, 标记)
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
    });
    // 这是一个代码块
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be executed once(只执行一次的代码放这里)
    });
    // 延迟两秒执行
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^{
        // 延时后只在主队列执行
    });
    
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
